package net.kem.android.positioner;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.location.Location;
import android.os.Parcel;
import android.os.Parcelable;

/**
 * POI structure:
 * Key: 	POI_<poi.ID>
 * Value:	id(int) | type(int) | name(String) | lat(float) | long(float) | alt(float) | accuracy(int) | radius(int) | notes(String)
 * @author Zhenya
 *
 */
public class POI implements Parcelable, Comparable<POI> {
	private static final char DELIMITER = (char)3;
	private static final String STORE_TEMPLATE = "%d"+DELIMITER+"%d"+DELIMITER+"%s"+DELIMITER
			+"%g"+DELIMITER+"%g"+DELIMITER+"%g"+DELIMITER
			+"%f"+DELIMITER+"%d"+DELIMITER+"%s";
	private static final Pattern LOAD_PATTERN = Pattern.compile("(\\d+)"+DELIMITER+"(\\d+)"+DELIMITER+"(.+)"
			+DELIMITER+"(\\d+\\.?\\d*)"+DELIMITER+"(\\d+\\.?\\d*)"+DELIMITER+"(\\d+\\.?\\d*)"
			+DELIMITER+"(\\d+\\.?\\d*)"+DELIMITER+"(\\d+)"+DELIMITER+"(.*)");
	private int id;
	private int type;
	private String name;
//	private GeoPoint coordinates;
	private Location coordinates;
	private int radius;
	private String notes;

	private int resourceDrawable;
	private PendingIntent proximityIntent;

	public POI() {
		init(0, 0, "", 0, 0);
	}
	POI(int id, String name) {
		init(id, 0, name, 0, 0);
	}
	POI(int id, int type, String name, Location coordinates) {
		init(id, type, name, coordinates.getLatitude(), coordinates.getLongitude());
	}

	POI(String name, String coords) {
		String[] latLon = coords.split(";");
		float latitude = Float.parseFloat(latLon[0]);
		float longitude = Float.parseFloat(latLon[1]);
		int id = Integer.parseInt(latLon[2]);
		int type = Integer.parseInt(latLon[3]);
		init(id, type, name, latitude, longitude);
	}

	POI(int id, int type, String name, double latitude, double longitude) {
		init(id, type, name, latitude, longitude);
	}

	public POI(int id, int type, String name, double lat, double lon, double alt, float accuracy, int radius, String notes) {
		this.id= id;
		this.type = type;
		this.name = name;
		this.coordinates = new Location("POI_" + id);
		this.coordinates.setLatitude(lat);
		this.coordinates.setLongitude(lon);
		this.coordinates.setAltitude(alt);
		this.coordinates.setAccuracy(accuracy);
		this.resourceDrawable = R.drawable.point_green;
	}

	private void init(int id, int type, String name, double latitude, double longitude) {
		this.id= id;
		this.type = type;
		this.name = name;
		this.coordinates = new Location("POI_" + name);
		this.coordinates.setLatitude(latitude);
		this.coordinates.setLongitude(longitude);
		this.resourceDrawable = R.drawable.point_green;
	}

	/**
	 *
	 * @param poiId
	 * @return
	 */
	static POI load(String poiKey) {
		POI res;
		String poiData = Settings.getValue(poiKey);//"POI_" + poiKey
		Matcher m = LOAD_PATTERN.matcher(poiData);
		if(m.matches()) {
			int id = Integer.parseInt(m.group(1));
			int type = Integer.parseInt(m.group(2));
			String name = m.group(3);
			double lat = Double.parseDouble(m.group(4));
			double lon = Double.parseDouble(m.group(5));
			double alt = Double.parseDouble(m.group(6));
			float accuracy = Float.parseFloat(m.group(7));
			int radius = Integer.parseInt(m.group(8));
			String notes = m.group(9);
			res = new POI(id, type, name, lat, lon, alt, accuracy, radius, notes);
		} else {
			res = null;
			//TODO log it.
		}
		return res;
	}

	POI store() {
		return store(this);
	}
	/**
	 * @param poi
	 * @return
	 */
	static POI store(POI poi) {
		Settings.storePOI(poi);
		return poi;
	}

	@SuppressLint("DefaultLocale")
	String getPOIdata() {
		String poiData = String.format(STORE_TEMPLATE, id, type, getName()
				, coordinates.getLatitude(), coordinates.getLongitude(), coordinates.getAltitude(), coordinates.getAccuracy()
				, radius, getNotes());
		return poiData;
	}

	/**
	 * @param poi
	 * @return
	 */
	static POI delete(POI poi) {
		Settings.deletePOI(poi);
		return poi;
	}

	@Override
	public boolean equals(Object other) {
		if(this == other) {
			return true;
		}
		if (other instanceof POI) {
			POI otherPOI = (POI)other;
			return id == otherPOI.id;
		}
		return false;
	}

	@Override
	public int compareTo(POI other) {
		if(other == null || other.name == null) {
			return -1;
		}
		return name.compareTo(other.name);
	}

	void setProximityIntent(PendingIntent proximityIntent) {
		this.proximityIntent = proximityIntent;
	}

	PendingIntent getProximityIntent() {
		return proximityIntent;
	}

	int getResourceDrawable() {
		return resourceDrawable;
	}

	boolean isDefined() {
		boolean res = coordinates.getLatitude() != 0 && coordinates.getLongitude() != 0;
		return res;
	}

	public Location getCoordinates() {
		return coordinates;
	}

	void setCoordinates(Location coordinates) {
		float accuracy = this.coordinates.getAccuracy();
		this.coordinates = new Location(coordinates);
		this.coordinates.setAccuracy(accuracy);
	}

	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public int getType() {
		return type;
	}
	public void setType(int type) {
		this.type = type;
	}
	public float getAccuracy() {
		return this.coordinates.getAccuracy();
	}
	public void setAccuracy(float accuracy) {
		this.coordinates.setAccuracy(accuracy);
	}
	public int getRadius() {
		return radius;
	}
	public void setRadius(int radius) {
		this.radius = radius;
	}
	public String getNotes() {
		return notes==null? "": notes;
	}
	public void setNotes(String notes) {
		this.notes = notes;
	}
	public String getName() {
		return name==null? "": name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setResourceDrawable(int resourceDrawable) {
		this.resourceDrawable = resourceDrawable;
	}
	public String toString() {
		String res = name + '@' + coordinates.getLatitude() + 'X' + coordinates.getLongitude();
		return res;
	}



	// Parcel part
	public POI(Parcel in) {
		id = in.readInt();
		type = in.readInt();
		name = in.readString();
		coordinates = in.readParcelable(null);
		radius = in.readInt();
		notes = in.readString();
	}

	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeInt(id);
		dest.writeInt(type);
		dest.writeString(name);
		dest.writeParcelable(coordinates, 0);
		dest.writeInt(radius);
		dest.writeString(notes);
	}

	public static final Parcelable.Creator<POI> CREATOR = new Parcelable.Creator<POI>() {
		@Override
		public POI createFromParcel(Parcel source) {
			return new POI(source); // using parcelable constructor
		}
		@Override
		public POI[] newArray(int size) {
			return new POI[size];
		}
	};
}